package com.yx.udp.util;

import java.net.DatagramPacket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class UdpPacketParser {

    // ====================== 协议包基类 ======================
    public static abstract class BasePacket {
        protected static final int HEADER_LOW = 0x55;
        protected static final int HEADER_HIGH = 0xAA;

        protected int cmdId;
        protected int cmdType;
        protected int globalCnt;

        public abstract byte[] toBytes();
        public abstract int getPacketSize();

        // 通用头部解析
        protected void parseHeader(ByteBuffer buffer) {
            // 验证包头
            if (buffer.get() != HEADER_LOW || buffer.get() != HEADER_HIGH) {
                throw new IllegalArgumentException("Invalid packet header");
            }

            // 命令ID (小端序)
            cmdId = buffer.getShort() & 0xFFFF;

            // 命令类型
            cmdType = buffer.get() & 0xFF;

            // Global Count (小端序)
            globalCnt = buffer.getShort() & 0xFFFF;

            // 总长度
            int totalLength = buffer.get() & 0xFF;
            if (totalLength != getPacketSize()) {
                throw new IllegalArgumentException("Invalid packet length");
            }
        }

        // 通用头部序列化
        protected void serializeHeader(ByteBuffer buffer) {
            buffer.put((byte) HEADER_LOW);
            buffer.put((byte) HEADER_HIGH);
            buffer.putShort((short) cmdId);
            buffer.put((byte) cmdType);
            buffer.putShort((short) globalCnt);
            buffer.put((byte) getPacketSize());
        }

        // CRC16 计算
        protected int calculateCrc(byte[] data, int length) {
            return Crc16Utils.calcCrc16(Arrays.copyOfRange(data, 0, length));
        }
    }

    // ====================== 握手协议包 ======================
    public static class HandshakePacket extends BasePacket {
        public static final int CMD_ID = 0x0101;
        public static final int PACKET_SIZE = 85;

        private int appId;
        private int hardwareStatus;
        private int protocolVersion;
        private String softwareVersion;
        private String deviceSN;
        private int weightPort;
        private int lockPort;
        private int tempControlPort;
        private int generalPort;
        private byte[] functionFlags = new byte[4];
        private int crc;

        public HandshakePacket() {
            cmdId = CMD_ID;
        }

        @Override
        public int getPacketSize() {
            return PACKET_SIZE;
        }

        public static HandshakePacket parse(DatagramPacket packet) {
            return parse(packet.getData(), packet.getOffset(), packet.getLength());
        }

        public static HandshakePacket parse(byte[] data) {
            return parse(data, 0, data.length);
        }

        public static HandshakePacket parse(byte[] data, int offset, int length) {
            if (length < PACKET_SIZE) {
                throw new IllegalArgumentException("Packet too small for handshake");
            }

            ByteBuffer buffer = ByteBuffer.wrap(data, offset, length)
                    .order(ByteOrder.LITTLE_ENDIAN);

            HandshakePacket packet = new HandshakePacket();
            packet.parseHeader(buffer);

            // APP ID
            packet.appId = buffer.get() & 0xFF;

            // 硬件状态
            packet.hardwareStatus = buffer.get() & 0xFF;

            // 协议版本
            packet.protocolVersion = buffer.get() & 0xFF;

            // 软件版本 (32字节)
            byte[] softwareBytes = new byte[32];
            buffer.get(softwareBytes);
            packet.softwareVersion = new String(softwareBytes).trim();

            // 设备SN (32字节)
            byte[] snBytes = new byte[32];
            buffer.get(snBytes);
            packet.deviceSN = new String(snBytes).trim();

            // 端口配置
            packet.weightPort = 7000 + (buffer.get() & 0xFF);
            packet.lockPort = 7000 + (buffer.get() & 0xFF);
            packet.tempControlPort = 7000 + (buffer.get() & 0xFF);
            packet.generalPort = 7000 + (buffer.get() & 0xFF);

            // 功能标志 (4字节)
            buffer.get(packet.functionFlags);

            // CRC
            packet.crc = buffer.getShort() & 0xFFFF;

            // 验证CRC
            int calcCrc = packet.calculateCrc(data, PACKET_SIZE - 2);
            if (calcCrc != packet.crc) {
                throw new IllegalArgumentException("CRC verification failed");
            }

            return packet;
        }

        @Override
        public byte[] toBytes() {
            ByteBuffer buffer = ByteBuffer.allocate(PACKET_SIZE)
                    .order(ByteOrder.LITTLE_ENDIAN);

            serializeHeader(buffer);

            // APP ID
            buffer.put((byte) appId);

            // 硬件状态
            buffer.put((byte) hardwareStatus);

            // 协议版本
            buffer.put((byte) protocolVersion);

            // 软件版本
            byte[] softwareBytes = new byte[32];
            byte[] srcSoftware = softwareVersion.getBytes();
            System.arraycopy(srcSoftware, 0, softwareBytes, 0,
                    Math.min(srcSoftware.length, 32));
            buffer.put(softwareBytes);

            // 设备SN
            byte[] snBytes = new byte[32];
            byte[] srcSN = deviceSN.getBytes();
            System.arraycopy(srcSN, 0, snBytes, 0,
                    Math.min(srcSN.length, 32));
            buffer.put(snBytes);

            // 端口配置
            buffer.put((byte) (weightPort - 7000));
            buffer.put((byte) (lockPort - 7000));
            buffer.put((byte) (tempControlPort - 7000));
            buffer.put((byte) (generalPort - 7000));

            // 功能标志
            buffer.put(functionFlags);

            // 计算并写入CRC
            byte[] packetData = buffer.array();
            int crcValue = calculateCrc(packetData, PACKET_SIZE - 2);
            buffer.put((byte) (crcValue & 0xFF));       // CRC低字节
            buffer.put((byte) ((crcValue >> 8) & 0xFF)); // CRC高字节

            return buffer.array();
        }

        // Getters and Setters
        public int getAppId() { return appId; }
        public void setAppId(int appId) { this.appId = appId; }

        public int getHardwareStatus() { return hardwareStatus; }
        public void setHardwareStatus(int hardwareStatus) {
            this.hardwareStatus = hardwareStatus;
        }

        public int getProtocolVersion() { return protocolVersion; }
        public void setProtocolVersion(int protocolVersion) {
            this.protocolVersion = protocolVersion;
        }

        public String getSoftwareVersion() { return softwareVersion; }
        public void setSoftwareVersion(String softwareVersion) {
            this.softwareVersion = softwareVersion;
        }

        public String getDeviceSN() { return deviceSN; }
        public void setDeviceSN(String deviceSN) {
            this.deviceSN = deviceSN;
        }

        public int getWeightPort() { return weightPort; }
        public void setWeightPort(int weightPort) {
            this.weightPort = weightPort;
        }

        public int getLockPort() { return lockPort; }
        public void setLockPort(int lockPort) {
            this.lockPort = lockPort;
        }

        public int getTempControlPort() { return tempControlPort; }
        public void setTempControlPort(int tempControlPort) {
            this.tempControlPort = tempControlPort;
        }

        public int getGeneralPort() { return generalPort; }
        public void setGeneralPort(int generalPort) {
            this.generalPort = generalPort;
        }

        public byte[] getFunctionFlags() { return functionFlags; }
        public void setFunctionFlags(byte[] functionFlags) {
            this.functionFlags = functionFlags;
        }

        public boolean hasTemperatureControl() {
            return (functionFlags[0] & 0x01) != 0;
        }

        public boolean hasBackupBattery() {
            return (functionFlags[0] & 0x02) != 0;
        }
    }

    // ====================== 数据协议包 ======================
    public static class DataPacket extends BasePacket {
        public static final int CMD_ID = 0x0201;
        public static final int PACKET_SIZE = 64;

        private int sensorId;
        private float temperature;
        private float humidity;
        private int batteryLevel;
        private long timestamp;
        private int crc;

        public DataPacket() {
            cmdId = CMD_ID;
        }

        @Override
        public int getPacketSize() {
            return PACKET_SIZE;
        }

        public static DataPacket parse(byte[] data) {
            return parse(data, 0, data.length);
        }

        public static DataPacket parse(byte[] data, int offset, int length) {
            if (length < PACKET_SIZE) {
                throw new IllegalArgumentException("Packet too small for data");
            }

            ByteBuffer buffer = ByteBuffer.wrap(data, offset, length)
                    .order(ByteOrder.LITTLE_ENDIAN);

            DataPacket packet = new DataPacket();
            packet.parseHeader(buffer);

            // 传感器ID
            packet.sensorId = buffer.getInt();

            // 温度 (4字节浮点数)
            packet.temperature = buffer.getFloat();

            // 湿度 (4字节浮点数)
            packet.humidity = buffer.getFloat();

            // 电池电量
            packet.batteryLevel = buffer.get() & 0xFF;

            // 时间戳 (8字节)
            packet.timestamp = buffer.getLong();

            // 保留字段 (跳过)
            buffer.position(buffer.position() + 32);

            // CRC
            packet.crc = buffer.getShort() & 0xFFFF;

            // 验证CRC
            int calcCrc = packet.calculateCrc(data, PACKET_SIZE - 2);
            if (calcCrc != packet.crc) {
                throw new IllegalArgumentException("CRC verification failed");
            }

            return packet;
        }

        @Override
        public byte[] toBytes() {
            ByteBuffer buffer = ByteBuffer.allocate(PACKET_SIZE)
                    .order(ByteOrder.LITTLE_ENDIAN);

            serializeHeader(buffer);

            // 传感器ID
            buffer.putInt(sensorId);

            // 温度
            buffer.putFloat(temperature);

            // 湿度
            buffer.putFloat(humidity);

            // 电池电量
            buffer.put((byte) batteryLevel);

            // 时间戳
            buffer.putLong(timestamp);

            // 保留字段 (填充0)
            byte[] reserved = new byte[32];
            buffer.put(reserved);

            // 计算并写入CRC
            byte[] packetData = buffer.array();
            int crcValue = calculateCrc(packetData, PACKET_SIZE - 2);
            buffer.put((byte) (crcValue & 0xFF));       // CRC低字节
            buffer.put((byte) ((crcValue >> 8) & 0xFF)); // CRC高字节

            return buffer.array();
        }

        // Getters and Setters
        public int getSensorId() { return sensorId; }
        public void setSensorId(int sensorId) { this.sensorId = sensorId; }

        public float getTemperature() { return temperature; }
        public void setTemperature(float temperature) {
            this.temperature = temperature;
        }

        public float getHumidity() { return humidity; }
        public void setHumidity(float humidity) {
            this.humidity = humidity;
        }

        public int getBatteryLevel() { return batteryLevel; }
        public void setBatteryLevel(int batteryLevel) {
            this.batteryLevel = batteryLevel;
        }

        public long getTimestamp() { return timestamp; }
        public void setTimestamp(long timestamp) {
            this.timestamp = timestamp;
        }
    }

    // ====================== 控制协议包 ======================
    public static class ControlPacket extends BasePacket {
        public static final int CMD_ID = 0x0301;
        public static final int PACKET_SIZE = 32;

        private int commandType;
        private int targetDevice;
        private int parameter1;
        private int parameter2;
        private int crc;

        public ControlPacket() {
            cmdId = CMD_ID;
        }

        @Override
        public int getPacketSize() {
            return PACKET_SIZE;
        }

        public static ControlPacket parse(byte[] data) {
            return parse(data, 0, data.length);
        }

        public static ControlPacket parse(byte[] data, int offset, int length) {
            if (length < PACKET_SIZE) {
                throw new IllegalArgumentException("Packet too small for control");
            }

            ByteBuffer buffer = ByteBuffer.wrap(data, offset, length)
                    .order(ByteOrder.LITTLE_ENDIAN);

            ControlPacket packet = new ControlPacket();
            packet.parseHeader(buffer);

            // 命令类型
            packet.commandType = buffer.get() & 0xFF;

            // 目标设备
            packet.targetDevice = buffer.get() & 0xFF;

            // 参数1
            packet.parameter1 = buffer.getInt();

            // 参数2
            packet.parameter2 = buffer.getInt();

            // 保留字段 (跳过)
            buffer.position(buffer.position() + 16);

            // CRC
            packet.crc = buffer.getShort() & 0xFFFF;

            // 验证CRC
            int calcCrc = packet.calculateCrc(data, PACKET_SIZE - 2);
            if (calcCrc != packet.crc) {
                throw new IllegalArgumentException("CRC verification failed");
            }

            return packet;
        }

        @Override
        public byte[] toBytes() {
            ByteBuffer buffer = ByteBuffer.allocate(PACKET_SIZE)
                    .order(ByteOrder.LITTLE_ENDIAN);

            serializeHeader(buffer);

            // 命令类型
            buffer.put((byte) commandType);

            // 目标设备
            buffer.put((byte) targetDevice);

            // 参数1
            buffer.putInt(parameter1);

            // 参数2
            buffer.putInt(parameter2);

            // 保留字段 (填充0)
            byte[] reserved = new byte[16];
            buffer.put(reserved);

            // 计算并写入CRC
            byte[] packetData = buffer.array();
            int crcValue = calculateCrc(packetData, PACKET_SIZE - 2);
            buffer.put((byte) (crcValue & 0xFF));       // CRC低字节
            buffer.put((byte) ((crcValue >> 8) & 0xFF)); // CRC高字节

            return buffer.array();
        }

        // Getters and Setters
        public int getCommandType() { return commandType; }
        public void setCommandType(int commandType) {
            this.commandType = commandType;
        }

        public int getTargetDevice() { return targetDevice; }
        public void setTargetDevice(int targetDevice) {
            this.targetDevice = targetDevice;
        }

        public int getParameter1() { return parameter1; }
        public void setParameter1(int parameter1) {
            this.parameter1 = parameter1;
        }

        public int getParameter2() { return parameter2; }
        public void setParameter2(int parameter2) {
            this.parameter2 = parameter2;
        }
    }

    // ====================== 协议解析器 ======================
    public static class PacketParser {
        private static final Map<Integer, PacketParser> parsers = new HashMap<>();

        static {
            // 注册支持的协议类型
            registerParser(HandshakePacket.CMD_ID, data -> HandshakePacket.parse(data));
            registerParser(DataPacket.CMD_ID, data -> DataPacket.parse(data));
            registerParser(ControlPacket.CMD_ID, data -> ControlPacket.parse(data));
        }

        public interface PacketFactory {
            BasePacket parse(byte[] data);
        }

        public static void registerParser(int cmdId, PacketFactory factory) {
            parsers.put(cmdId, new PacketParser(factory));
        }

        private final PacketFactory factory;

        private PacketParser(PacketFactory factory) {
            this.factory = factory;
        }

        public static BasePacket parse(DatagramPacket packet) {
            return parse(packet.getData(), packet.getOffset(), packet.getLength());
        }

        public static BasePacket parse(byte[] data) {
            return parse(data, 0, data.length);
        }

        public static BasePacket parse(byte[] data, int offset, int length) {
            // 验证最小长度
            if (length < 7) { // 包头2 + 命令ID2 + 命令类型1 + GlobalCnt2
                throw new IllegalArgumentException("Packet too small");
            }

            // 验证包头
            if (data[offset] != (byte) BasePacket.HEADER_LOW ||
                    data[offset + 1] != (byte) BasePacket.HEADER_HIGH) {
                throw new IllegalArgumentException("Invalid packet header");
            }

            // 提取命令ID (小端序)
            int cmdId = ((data[offset + 3] & 0xFF) << 8) | (data[offset + 2] & 0xFF);

            // 查找对应的解析器
            PacketParser parser = parsers.get(cmdId);
            if (parser == null) {
                throw new IllegalArgumentException("Unsupported command ID: 0x" +
                        Integer.toHexString(cmdId));
            }

            return parser.factory.parse(data);
        }
    }

    // ====================== CRC16 工具类 ======================
    public static class Crc16Utils {
        // CRC16查找表（与C代码完全一致）
        private static final int[] CRC16_TABLE = {
                0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
                0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
                0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
                0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
                0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
                0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
                0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
                0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
                0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
                0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
                0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
                0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
                0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
                0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
                0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
                0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
                0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
                0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
                0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
                0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
                0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
                0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
                0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
                0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
                0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
                0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
                0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
                0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
                0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
                0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
                0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
                0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
        };

        // 计算CRC16 (与C函数完全兼容)
        public static int calcCrc16(byte[] data, int crcSeed) {
            int crc = crcSeed & 0xFFFF;  // 确保只有低16位有效

            for (byte b : data) {
                // 将字节转换为无符号值 (0-255)
                int unsignedByte = b & 0xFF;

                // 计算中间值 (当前字节与CRC低8位异或)
                int temp = unsignedByte ^ (crc & 0xFF);

                // 右移CRC 8位 (高位补0)
                crc = (crc >>> 8) & 0xFFFF;

                // 查表并更新CRC值
                crc = crc ^ CRC16_TABLE[temp];
            }

            return crc & 0xFFFF;  // 确保返回16位无符号值
        }

        // 简化版本 (使用默认种子0xFFFF)
        public static int calcCrc16(byte[] data) {
            return calcCrc16(data, 0xFFFF);
        }


    }

}